/*
 * @Author: 张宇捷
 * @Date: 2025-10-14 15:06:29
 * @LastEditors: 张宇捷
 * @LastEditTime: 2025-10-17 16:48:40
 * @Description: 文件描述
 */

/*
封装一个对象迭代的方法
    + 基于传统的for/in循坏，会存在一些弊端[性能较差；既可以迭代私有的，也可以迭代公有的；只能迭代“可枚举，非Symbol类型”的属性]   
    + Symbol是Js中的原始数据，是具有唯一性的，即使有相同描述字符串的Symbol，依旧是不同的
    + 解决思路：获取对象所有的私有属性[私有的，可枚举的，不可枚举的，Symbol类型的，不论类型]
      Object.getOwnPropertyNames(arr)--> 获取对象所有非Symbol类型的私有属性
      Object.getOwnPropertySymbols(arr)---> 获取对象所有Symbol类型的私有属性
      获取所有的私有属性：
        let keys = Object.getOwnPropertyNames(arr).concat(Object.getOwnPropertySymbols(arr));
      基于ES6获取所有私有属性 [弊端：不兼容IE]
        let keys = Reflect.ownKeys(arr);
    
*/
const each = function each(obj, callback) {
  if (obj === null || typeof obj !== "object")
    throw new TypeError("obj is not a object");
  if (typeof callback !== "function")
    throw new TypeError("callback is not a function");
  let keys = Reflect.ownKeys(obj);
  keys.forEach((key) => {
    let value = obj[key];
    // 每一次迭代都执行回调函数
    callback(value, key);
  });
};

/*createElement:创建虚拟DOM对象*/
export function createElement(ele, props, ...children) {
  let vitualDOM = {
    $$typeof: Symbol("React.element"),
    ref: null,
    key: null,
    type: null,
    props: {},
  };
  vitualDOM.type = ele;
  let length = children.length;
  if (props !== null) {
    vitualDOM.props = { ...props };
  }
  if (length === 1) vitualDOM.props.children = children[0];
  if (length > 1) vitualDOM.props.children = children;
  return vitualDOM;
}
/*render:把虚拟DOM转变为真实DOM */
export function render(virtualDOM, container) {
  let { type, props } = virtualDOM;
  if (typeof type === "string") {
    // 存储的是标签名，动态创建一个标签
    let ele = document.createElement(type);
    // 使用setAttribute方法设置标签的属性,getAttribute方法获取标签的属性,removeAttribute方法删除标签的属性
    each(props, (value, key) => {
      // className的处理，value存储的是样式类名
      if (key === "className") {
        ele.className = value;
      }
      // value的处理，value存储的是样式对象
      if (key === "style") {
        each(value, (value, key) => {
          // style.key是给style加key这个属性，[]是用于动态获取style属性
          ele.style[key] = value;
        });
        return;
      }
      // 字节点的处理
      if (key === "children") {
        let children = value;
        // 如果children是数组，则遍历children，将children中的元素转为真实DOM，塞入ele中
        if (!Array.isArray(children)) children = [children];
        children.forEach((child) => {
          // 如果是文本节点，直接创建，塞入当前ele中
          if (/^(string|number)$/.test(typeof child))
            ele.appendChild(document.createTextNode(child));
          // 如果是virtualDOM递归调用Render
          if (typeof child === "object") render(child, ele);
        });
        return;
      }
      ele.setAttribute(key, value);
    });
    // 将标签存入容器中
    container.appendChild(ele);
  }
}
